﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Silverlight.ControlToolkit.Windows;

namespace Silverlight.ControlToolkit.Validator
{
    [TemplatePart(Name = ErrorProvider.RootElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = ErrorProvider.MessageTextElement, Type = typeof(TextBlock))]
    [TemplateVisualState(Name = ErrorProvider.ShowingState, GroupName = ErrorProvider.CommonStatesGroup), TemplateVisualState(Name = ErrorProvider.NormalState, GroupName = ErrorProvider.CommonStatesGroup), TemplateVisualState(Name = ErrorProvider.MouseOverState, GroupName = ErrorProvider.CommonStatesGroup), TemplateVisualState(Name = ErrorProvider.ClosingState, GroupName = ErrorProvider.CommonStatesGroup)]
    public class ErrorProvider : Control
    {

        private const string RootElement = "RootElement";
        private const string MessageTextElement = "MessageTextElement";

        private const string CommonStatesGroup = "CommonStates";
        private const string NormalState = "Normal";
        private const string ShowingState = "Showing";
        private const string MouseOverState = "MouseOver";
        private const string ClosingState = "Closing";

        private FrameworkElement _rootElement;
        private TextBlock _messageTextElement;

        private FrameworkElement _owner;
        private WindowPanel _parentWindow;

        private ErrorProvider(): base()
        {
            //this.DefaultStyleKey = typeof(ErrorProvider);
        }

        public static Style DefaultStyle { get; set; }

        public static string DefaultStyleXaml
        {
            set
            {
                DefaultStyle = System.Windows.Markup.XamlReader.Load(value) as Style;
            }

        }
        public static ControlTemplate DefaultTemplate { get; set; }

        public static string DefaultTemplateXaml
        {
            set
            {
                DefaultTemplate = System.Windows.Markup.XamlReader.Load(value) as ControlTemplate;
            }

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _rootElement = (FrameworkElement)GetTemplateChild(ErrorProvider.RootElement);
            _messageTextElement = (TextBlock)GetTemplateChild(ErrorProvider.MessageTextElement);

        }

        public static readonly DependencyProperty ErrorMessageProperty =
                DependencyProperty.RegisterAttached("ErrorMessage", typeof(string), typeof(ErrorProvider), new PropertyMetadata(OnErrorMessageChanged));


        /// <summary>
        /// Gets the current datatype associated with the control
        /// </summary>
        /// <param name="d">Dependecy Object / Control</param>
        /// <returns></returns>
        public static string GetErrorMessage(DependencyObject d)
        {
            return (string)d.GetValue(ErrorMessageProperty);
        }

        /// <summary>
        /// Sets the Data Type property
        /// </summary>
        /// <param name="d">Dependecy Object / Control</param>
        /// <param name="value">Data Type to be set on the control</param>
        public static void SetErrorMessage(DependencyObject d, string value)
        {
            d.SetValue(ErrorMessageProperty, value);
        }

        /// <summary>
        /// Handles changes to the ErrorMessage property.
        /// </summary>
        /// <param name="d">Dependecy Object / Control</param>
        /// <param name="e">Event args</param>
        private static void OnErrorMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

            ErrorProvider errorIndicator = d.GetValue(ErrorIndicatorProperty) as ErrorProvider;
            if (errorIndicator == null) //First time
            {
                errorIndicator = new ErrorProvider();
                errorIndicator.ApplyDefaultStyleTemplate(DefaultStyle, DefaultTemplate);
            }

            if (e.NewValue != null && e.NewValue.ToString().Trim().Length > 0)
            {
                SetErrorIndicator(d, errorIndicator);

                if (errorIndicator._messageTextElement != null)
                    errorIndicator._messageTextElement.Text = e.NewValue.ToString();
                else
                    ToolTipService.SetToolTip(errorIndicator, e.NewValue);
            }
            else //Clear the message
            {
                d.ClearValue(ErrorIndicatorProperty);
            }


        }


        private static readonly DependencyProperty ErrorIndicatorProperty =
                DependencyProperty.RegisterAttached("ErrorIndicator", typeof(ErrorProvider), typeof(ErrorProvider), new PropertyMetadata(OnErrorIndicatorChanged));


        /// <summary>
        /// Gets the current datatype associated with the control
        /// </summary>
        /// <param name="d">Dependecy Object / Control</param>
        /// <returns></returns>
        private static ErrorProvider GetErrorIndicator(DependencyObject d)
        {
            return (ErrorProvider)d.GetValue(ErrorIndicatorProperty);
        }

        /// <summary>
        /// Sets the Data Type property
        /// </summary>
        /// <param name="d">Dependecy Object / Control</param>
        /// <param name="value">Data Type to be set on the control</param>
        private static void SetErrorIndicator(DependencyObject d, ErrorProvider value)
        {
            d.SetValue(ErrorIndicatorProperty, value);
        }

        /// <summary>
        /// Handles changes to the ErrorIndicator property.
        /// </summary>
        /// <param name="d">Dependecy Object / Control</param>
        /// <param name="e">Event args</param>
        private static void OnErrorIndicatorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ErrorProvider oldErrorIndicator = e.OldValue as ErrorProvider;
            if (oldErrorIndicator != null) //Hide the old indicator if any
            {
                if (oldErrorIndicator.Parent is Popup)
                {
                    ((Popup)oldErrorIndicator.Parent).IsOpen = false;

                    if (oldErrorIndicator._owner != null)
                    {
                        oldErrorIndicator._owner.SizeChanged -= new SizeChangedEventHandler(oldErrorIndicator._owner_SizeChanged);

                        if (oldErrorIndicator._parentWindow != null)
                        {
                            oldErrorIndicator._parentWindow.Dragged -= new RoutedEventHandler(oldErrorIndicator._parentWindow_Dragged);
                            oldErrorIndicator._parentWindow.DialogBoxClosed -= new DialogBoxClosedEventHandler(oldErrorIndicator._parentWindow_DialogBoxClosed);
                        }
                    }

                    Application.Current.Host.Content.Resized -= new EventHandler(oldErrorIndicator.Content_Resized);

                }

                oldErrorIndicator.MouseEnter -= new MouseEventHandler(newErrorIndicator_MouseEnter);
                oldErrorIndicator.MouseLeave -= new MouseEventHandler(newErrorIndicator_MouseLeave);

                VisualStateManager.GoToState(oldErrorIndicator, ClosingState, true);


            }

            if (e.NewValue != null)
            {

                ErrorProvider newErrorIndicator = e.NewValue as ErrorProvider;

                if (d is FrameworkElement)
                {
                    newErrorIndicator._owner = d as FrameworkElement;
                    newErrorIndicator._owner.SizeChanged += new SizeChangedEventHandler(newErrorIndicator._owner_SizeChanged);

                    newErrorIndicator._parentWindow = newErrorIndicator._owner.GetParentByType(typeof(WindowPanel)) as WindowPanel;
                    if (newErrorIndicator._parentWindow != null)
                    {
                        newErrorIndicator._parentWindow.Dragged += new RoutedEventHandler(newErrorIndicator._parentWindow_Dragged);
                        newErrorIndicator._parentWindow.DialogBoxClosed += new DialogBoxClosedEventHandler(newErrorIndicator._parentWindow_DialogBoxClosed);
                    }


                    FrameworkElement objRoot = Application.Current.RootVisual as FrameworkElement;
                    if (newErrorIndicator._owner != objRoot)
                        Application.Current.Host.Content.Resized += new EventHandler(newErrorIndicator.Content_Resized);
                }

                newErrorIndicator.IsTabStop = false;
                newErrorIndicator.SizeChanged += new SizeChangedEventHandler(newErrorIndicator_SizeChanged);
                newErrorIndicator.MouseEnter += new MouseEventHandler(newErrorIndicator_MouseEnter);
                newErrorIndicator.MouseLeave += new MouseEventHandler(newErrorIndicator_MouseLeave);

                Popup parentPopup = new Popup();
                parentPopup.IsHitTestVisible = false;

                parentPopup.Child = newErrorIndicator;

                parentPopup.IsOpen = true;

                VisualStateManager.GoToState(newErrorIndicator, ShowingState, true);

                VisualStateManager.GoToState(newErrorIndicator, NormalState, true);

            }

        }

        static void newErrorIndicator_MouseLeave(object sender, MouseEventArgs e)
        {
            ErrorProvider errorIndicator = sender as ErrorProvider;
            if (errorIndicator != null)
            {
                VisualStateManager.GoToState(errorIndicator, NormalState, true);
            }
        }

        static void newErrorIndicator_MouseEnter(object sender, MouseEventArgs e)
        {
            ErrorProvider errorIndicator = sender as ErrorProvider;
            if (errorIndicator != null)
            {
                VisualStateManager.GoToState(errorIndicator, MouseOverState, true);
            }
        }

        private void _parentWindow_DialogBoxClosed(object sender, DialogBoxEventArgs e)
        {
            if (this._owner != null)
            {
                this._owner.ClearValue(ErrorProvider.ErrorIndicatorProperty);
            }
        }

        private void _parentWindow_Dragged(object sender, RoutedEventArgs e)
        {
            PerformPlacement(this);
        }

        private static void PerformPlacement(ErrorProvider errorIndicator)
        {
            if (errorIndicator != null && errorIndicator._owner != null && errorIndicator.Parent is Popup)
            {
                Popup parentPopup = errorIndicator.Parent as Popup;
                parentPopup.PlaceBesidesOwner(errorIndicator._owner, Corner.RightCenter, new Thickness(2, 0, 0, 0));
            }
        }

        private void _owner_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            PerformPlacement(this);
        }

        private void Content_Resized(object sender, EventArgs e)
        {
            PerformPlacement(this);
        }

        static void newErrorIndicator_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ErrorProvider errorIndicator = sender as ErrorProvider;

            if (errorIndicator != null)
            {
                PerformPlacement(errorIndicator);
                errorIndicator.SizeChanged -= new SizeChangedEventHandler(newErrorIndicator_SizeChanged);
            }

        }





    }
}
